﻿using System.Linq;
using Daemon.Common;
using Daemon.Common.Helpers;
using Daemon.Infrustructure.EF;
using Daemon.Repository.EF.Enums;
using Daemon.Repository.Contract;
using Daemon.Model;
using System;
using System.Linq.Expressions;
using System.Collections.Generic;
using Daemon.Model.Entities;
using Daemon.Data.Substructure.Enums;

namespace Daemon.Repository.EF
{
	public class TakeAwayUserOrderRepository : Repository<TakeAwayUserOrder>, ITakeAwayUserOrderRepository
	{
		private readonly ITakeAwayUserOrderDetailRepository _takeAwayUserOrderDetailRepository;

		private readonly ITakeAwayIntegeralSettingRepository _takeAwayIntegeralSettingRepository;

		private readonly ITakeAwayUserAccountRepository _takeAwayUserAccountRepository;

		private readonly ITakeAwayAccountTransactionRepository _takeAwayAccountTransactionRepository;

		private readonly ITakeAwayIntegeralTransactionRepository _takeAwayIntegeralTransactionRepository;

		protected override Expression<Func<TakeAwayUserOrder, int>> PrimaryKeyExpression => r => r.Id;

		public TakeAwayUserOrderRepository(ApiDBContent context
			, ITakeAwayUserOrderDetailRepository takeAwayUserOrderDetailRepository,
			ITakeAwayIntegeralSettingRepository takeAwayIntegeralSettingRepository
			, ITakeAwayUserAccountRepository takeAwayUserAccountRepository,
			ITakeAwayAccountTransactionRepository takeAwayAccountTransactionRepository,
			ITakeAwayIntegeralTransactionRepository takeAwayIntegeralTransactionRepository) : base(context)
		{
			_takeAwayUserOrderDetailRepository = takeAwayUserOrderDetailRepository;
			_takeAwayIntegeralSettingRepository = takeAwayIntegeralSettingRepository;
			_takeAwayUserAccountRepository = takeAwayUserAccountRepository;
			_takeAwayAccountTransactionRepository = takeAwayAccountTransactionRepository;
			_takeAwayIntegeralTransactionRepository = takeAwayIntegeralTransactionRepository;
		}

		public TakeAwayUserOrder UpdateUserOrder(TakeAwayUserOrder order)
		{
			var userOrder = UpdateByDBContext(order, Context);
			SetRelationships(new List<Relationship>() { new Relationship() { Name = TakeAwayUserOrderRelationShipEnum.OrderDetail.ToString() } });
			GetUserOrderDetail(new List<TakeAwayUserOrder>() { userOrder });
			return userOrder;
		}

		protected override void UpdateEntitiesBeforeCreate(IEnumerable<TakeAwayUserOrder> entities, ApiDBContent context)
		{
			foreach (var entity in entities)
			{
				entity.IsRead = false;
				entity.OrderNumber = GenerateOrderNo.Gener("", "YMYY", 2);
				entity.AddTime = DateTime.Now;
				if (entity.IsTakeAway == 1)
				{
					entity.TakeAwayNumber = GenerateOrderNo.GeneratePickUpCode();
				}
			}
		}

		protected override void DeleteRelationships(IEnumerable<TakeAwayUserOrder> entities, ApiDBContent db)
		{
			var orderIds = entities.Select(r => r.Id).ToList();
			var userOrderDetails = _takeAwayUserOrderDetailRepository.FindAll().Where(r => orderIds.Contains(r.OrderId));
			_takeAwayUserOrderDetailRepository.DeleteRange(userOrderDetails);
			base.DeleteRelationships(entities, db);
		}

		protected override void SaveRelationships(TakeAwayUserOrder entity, TakeAwayUserOrder entityWithRelationships, ApiDBContent db, short entityORMType)
		{
			AddUserOrderDetail(entity, entityWithRelationships);
			base.SaveRelationships(entity, entityWithRelationships, db, entityORMType);
		}

		protected override void UpdateEntitiesAfterPatch(IEnumerable<TakeAwayUserOrder> entities, List<JsonPatchData> patchData, ApiDBContent context)
		{
			UpdateAccountTransaction(entities, patchData);

			base.UpdateEntitiesAfterPatch(entities, patchData, context);
		}

		protected override IEnumerable<TakeAwayUserOrder> IncludeRelationships(IEnumerable<TakeAwayUserOrder> entities, ApiDBContent db)
		{
			GetUserOrderDetail(entities);

			GetBoradInfo(entities);

			GetUserInfo(entities);

			return base.IncludeRelationships(entities, db);
		}

		private void GetUserInfo(IEnumerable<TakeAwayUserOrder> entities)
		{
			var userIds = entities.Select(r => r.UserId).ToList();
			var dicUsers = Context.TakeAwayUser.Where(r => userIds.Contains(r.Id)).ToDictionary(r => r.Id, r => r);
			foreach (var item in entities)
			{
				if (dicUsers.TryGetValue(item.UserId, out TakeAwayUser user))
				{
					item.UserInfo = user;
				}
			}
		}

		private void UpdateAccountTransaction(IEnumerable<TakeAwayUserOrder> entities, List<JsonPatchData> patchData)
		{
			var updateStatus = patchData.Find(r => r.Path == "Status");
			if (updateStatus == null)
			{
				return;
			}

			var userOrder = entities.FirstOrDefault(r => r.Id.ToString() == updateStatus.Id);
			var confirmOrder = Convert.ToInt32(updateStatus.Value) == (int)UserOrderStatusEnum.Success;
			if (!confirmOrder)
			{
				return;
			}

			var shopInfo = Context.TakeAwayShop.First(r => r.Id == userOrder.ShopId);
			if (!shopInfo.EnableSubContribute)
			{
				return;
			}

			var currentUser = Context.TakeAwayUser.First(r => r.Id == userOrder.UserId);
			if (currentUser == null || !currentUser.ParentId.HasValue)
			{
				return;
			}

			var parentUserAccount = Context.TakeAwayUserAccount.First(r => r.UserId == currentUser.ParentId);
			var integeralSetting = Context.TakeAwayIntegeralSetting.FirstOrDefault(r => r.ShopId == userOrder.ShopId);
			var integeral = userOrder.Price * integeralSetting.Integeral / integeralSetting.Money;
			var accountTransaction = new TakeAwayIntegeralTransaction() { AccountId = parentUserAccount.Id, AdjustCost = integeral, UserId = currentUser.Id, Description = $"下级用户{0}消费了{userOrder.Price}元钱,积分+{integeral}" };
			_takeAwayIntegeralTransactionRepository.AddByDBContext(accountTransaction);
		}

		private void GetBoradInfo(IEnumerable<TakeAwayUserOrder> entities)
		{
			var boardIds = entities.Where(r => r.BoardId.HasValue).Select(r => r.BoardId).ToList();
			var dicBorad = Context.TakeAwayBoard.Where(r => boardIds.Contains(r.Id)).ToDictionary(r => r.Id, r => r.BoardNumber);
			foreach (var entity in entities)
			{
				if (entity.BoardId.HasValue && dicBorad.TryGetValue(entity.BoardId.Value, out string boardName))
				{
					entity.BoardName = boardName;
				}
			}
		}

		private void GetUserOrderDetail(IEnumerable<TakeAwayUserOrder> entities)
		{
			if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, TakeAwayUserOrderRelationShipEnum.OrderDetail))
			{
				return;
			}

			var orderIds = entities.Select(r => r.Id).ToList();
			_takeAwayUserOrderDetailRepository.SetRelationships(new List<Model.Entities.Relationship>() { new Model.Entities.Relationship() { Name = TakeAwayUserOrderDetailRelationShipEnum.GoodInfo.ToString() } });
			var dicOrderDetail = _takeAwayUserOrderDetailRepository.IncludeRelationships(Context.TakeAwayUserOrderDetail.Where(r => orderIds.Contains(r.OrderId))).ToList().GroupBy(r => r.OrderId).ToDictionary(r => r.Key, r => r.ToList());
			var shopIds = entities.Select(r => r.ShopId).ToList();
			var dicShops = Context.TakeAwayShop.Where(r => shopIds.Contains(r.Id)).ToDictionary(r => r.Id, r => r);
			foreach (var entity in entities)
			{
				if (dicOrderDetail.TryGetValue(entity.Id, out List<TakeAwayUserOrderDetail> orderDetails))
				{
					entity.OrderDetails = orderDetails;
				}

				if (dicShops.TryGetValue(entity.ShopId, out TakeAwayShop shop))
				{
					entity.ShopName = shop.Name;
					entity.ShopPhoneNumber = shop.TelNumber;
					entity.ShopAddress = shop.Address;
				}
			}
		}

		private void AddUserOrderDetail(TakeAwayUserOrder entity, TakeAwayUserOrder entityWithRelationships)
		{
			entityWithRelationships.OrderDetails.ForEach(detail =>
			{
				detail.OrderId = entity.Id;
			});

			_takeAwayUserOrderDetailRepository.AddRangeByDBContext(entityWithRelationships.OrderDetails);
		}

		private void UpdateUserAccount(TakeAwayUserOrder entity)
		{
			UpdateUserAccountIntegeral(entity);
		}

		private void UpdateUserAccountIntegeral(TakeAwayUserOrder entity)
		{
			if (entity.PayType != 1)
			{
				return;
			}

			var integeralSetting = _takeAwayIntegeralSettingRepository.FindAll().OrderByDescending(r => r.Id).FirstOrDefault(r => r.ShopId == entity.ShopId);
			if (integeralSetting == null)
			{
				return;
			}

			var userAccount = _takeAwayUserAccountRepository.FindAll().FirstOrDefault(r => r.UserId == entity.UserId);
			var userAccountIntegeral = _takeAwayAccountTransactionRepository.FindAll().Where(r => r.UserId == entity.UserId).Select(r => r.AdjustCost).Sum();
			if (userAccount == null)
			{
				return;
			}

			var userUsedIntegeral = Convert.ToInt32(entity.Price);
			if (userUsedIntegeral > userAccountIntegeral)
			{
				return;
			}

			var accountTransaction = new TakeAwayAccountTransaction() { AccountId = userAccount.Id, AdjustCost = -userUsedIntegeral, UserId = userAccount.UserId, Description = $"用户{0}消费了{userUsedIntegeral}元钱,积分-{userUsedIntegeral}" };
			_takeAwayAccountTransactionRepository.AddByDBContext(accountTransaction);
		}
	}
}
